package org.xxpay.pay.channel.payeasepay;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import org.springframework.stereotype.Service;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.util.AmountUtil;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayNotify;
import org.xxpay.pay.channel.payeasepay.demo.CFCA.MerchantX509Cert;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: zhuxiao
 * @date: 18/12/13
 * @description: 首信易支付回调
 */
@Service
public class PayeasepayPayNotifyService extends BasePayNotify {

    private static final MyLog _log = MyLog.getLog(PayeasepayPayNotifyService.class);

    @Override
    public String getChannelName() {
        return PayeasepayConfig.CHANNEL_NAME_PAYEASEPAY;
    }

    @Override
    public JSONObject doNotify(Object notifyData) {
        String logPrefix = "【处理首信易支付回调】";
        _log.info("====== 开始处理首信易支付回调通知 ======");
        HttpServletRequest request = (HttpServletRequest) notifyData;
        JSONObject retObj = buildRetObj();
        Map<String, Object> payContext = new HashMap();
        PayOrder payOrder;
        String respString = PayeasepayConfig.RETURN_VALUE_SENT;
        try {
            String v_oid = request.getParameter("v_oid");                   // 订单编号
            String v_pmode = new String(request.getParameter("v_pmode").getBytes("ISO-8859-1"),"GBK");               // 支付方式
            String v_pstatus = request.getParameter("v_pstatus");           // 支付结果 20支付成功 30 支付失败
            String v_pstring = new String(request.getParameter("v_pstring").getBytes("ISO-8859-1"),"GBK");           // 支付结果说明
            String v_count = request.getParameter("v_count");               // 订单个数
            String v_amount = request.getParameter("v_amount");             // 订单金额
            String v_moneytype = request.getParameter("v_moneytype");       // 币种
            String v_sign = request.getParameter("v_sign");                 // CFCA校验

            Map<String,String> params = new HashMap<>();
            params.put("v_oid", v_oid);
            params.put("v_pstatus", v_pstatus);
            params.put("v_pstring", v_pstring);
            params.put("v_count", v_count);
            params.put("v_amount", v_amount);
            params.put("v_moneytype", v_moneytype);
            params.put("v_pmode", v_pmode);
            params.put("v_sign", v_sign);

            _log.info("{}请求数据:{}", logPrefix, params);

            //验证参数
            payContext.put("parameters", params);
            if(!verifyPayParams(payContext)) {
                retObj.put(PayConstant.RESPONSE_RESULT, PayeasepayConfig.RETURN_VALUE_FAIL);
                return retObj;
            }

            //拆分参数
            String[] resultoid = v_oid.split("[|][_][|]");
            String[] resultstatus = v_pstatus.split("[|][_][|]");
            String[] resultpstring = v_pstring.split("[|][_][|]");
            String[] resultamount = v_amount.split("[|][_][|]");
            String[] resultmoneytype = v_moneytype.split("[|][_][|]");
            for(int i = 0; i < resultoid.length; i++) {
                String status = resultstatus[i];
                if(!"1".equals(status)) {
                    respString = PayeasepayConfig.RETURN_VALUE_ERROR;
                    continue;
                }
                String payOrderId = resultoid[i];
                payOrder = commonService.payOrderService.findByPayOrderId(payOrderId);
                if(payOrder == null) {
                    respString = PayeasepayConfig.RETURN_VALUE_ERROR;
                    continue;
                }
                long outPayAmt = new BigDecimal(resultamount[i]).longValue();
                long dbPayAmt = new BigDecimal(AmountUtil.convertCent2Dollar(payOrder.getAmount() + "")).longValue();
                if (dbPayAmt != outPayAmt) {
                    _log.warn("{}金额不一致.payOrderId={},outPayAmt={},dbPayAmt", logPrefix, payOrderId, outPayAmt, dbPayAmt);
                    respString = PayeasepayConfig.RETURN_VALUE_ERROR;
                    continue;
                }
                // 处理订单
                byte payStatus = payOrder.getStatus(); // 0：订单生成，1：支付中，-1：支付失败，2：支付成功，3：业务处理完成，-2：订单过期

                if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) {
                    int updatePayOrderRows = commonService.payOrderService.updateStatus4Success(payOrder.getPayOrderId());
                    if (updatePayOrderRows != 1) {
                        _log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
                        retObj.put(PayConstant.RESPONSE_RESULT, "处理订单失败");
                        return retObj;
                    }
                    _log.error("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
                    payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
                }
                // 业务系统后端通知
                baseNotify4MchPay.doNotify(payOrder, true);
            }
            _log.info("====== 完成处理首信易支付回调通知 ======");

        }catch (Exception e) {
            _log.error(e, logPrefix + "处理异常");
            respString = PayeasepayConfig.RETURN_VALUE_ERROR;
        }
        retObj.put(PayConstant.RESPONSE_RESULT, respString);
        return retObj;
    }

    @Override
    public JSONObject doReturn(Object notifyData) {
        String logPrefix = "【处理首信易同步跳转】";
        _log.info("====== 开始处理首信易同步跳转 ======");
        HttpServletRequest request = (HttpServletRequest) notifyData;
        String v_oid = request.getParameter("v_oid");                                                            //订单编号
        String v_pmode = request.getParameter("v_pmode");                                                        //支付方式
        String v_pstatus = request.getParameter("v_pstatus");                                                    //支付结果 20支付成功 30 支付失败
        String v_pstring = request.getParameter("v_pstring");                                                    //支付结果说明
        String v_amount = request.getParameter("v_amount");                                                      //订单金额
        String v_moneytype = request.getParameter("v_moneytype");                                                //币种
        String v_sign = request.getParameter("v_sign");                                                          //CFCA校验

        Map<String,String> params = new HashMap<>();
        params.put("v_oid", v_oid);
        params.put("v_pstatus", v_pstatus);
        params.put("v_pstring", v_pstring);
        params.put("v_amount", v_amount);
        params.put("v_moneytype", v_moneytype);
        params.put("v_pmode", v_pmode);
        params.put("v_sign", v_sign);

        _log.info("{}请求数据:{}", logPrefix, params);

        // 构建返回对象
        JSONObject retObj = buildRetObj();
        if(params == null || params.isEmpty()) {
            retObj.put(PayConstant.RESPONSE_RESULT, WxPayNotifyResponse.fail("请求数据为空"));
            return retObj;
        }
        Map<String, Object> payContext = new HashMap();
        payContext.put("parameters", params);
        if(!verifyPayReturnParams(payContext)) {
            retObj.put(PayConstant.RESPONSE_RESULT, PayConstant.RETURN_ALIPAY_VALUE_FAIL);
            return retObj;
        }
        _log.info("{}验证支付通知数据及签名通过", logPrefix);

        PayOrder payOrder = (PayOrder)payContext.get("payOrder");
        String url = baseNotify4MchPay.createNotifyUrl(payOrder, "1");
        retObj.put(PayConstant.RESPONSE_RESULT, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS);
        retObj.put(PayConstant.JUMP_URL, url);
        _log.info("====== 完成处理首信易同步跳转 ======");
        return retObj;
    }

    /**
     * 验证首信易支付notify通知参数
     * @return
     */
    public boolean verifyPayParams(Map<String, Object> payContext) {
        Map<String,String> params = (Map<String,String>)payContext.get("parameters");

        //校验结果是否成功
        String status = params.get("v_pstatus");
        if(status == null || !"1".equals(status)) {
            _log.error("status={}",status);
            payContext.put("retMsg", "notify data failed");
            return false;
        }

        String oid = params.get("v_oid");		                // 商户订单号
        String total_amount = params.get("v_amount"); 		    // 支付金额
        if (org.springframework.util.StringUtils.isEmpty(oid)) {
            _log.error("Payeasepay Notify parameter oid is empty. oid={}", oid);
            payContext.put("retMsg", "oid is empty");
            return false;
        }
        if (org.springframework.util.StringUtils.isEmpty(total_amount)) {
            _log.error("Payeasepay Notify parameter total_amount is empty. total_amount={}", total_amount);
            payContext.put("retMsg", "total_amount is empty");
            return false;
        }
        String errorMessage;

        //PayeasepayConfig payeasepayConfig = new PayeasepayConfig(getPayParam(payOrder));
        // 验证签名
        String publicKey = getCertFilePath(getChannelName(), PayeasepayConfig.pubkeyName);
        String signSrc = params.get("v_oid") + params.get("v_pstatus") + params.get("v_amount") + params.get("v_moneytype") + params.get("v_count");
        String v_sign = params.get("v_sign");
        try {
            Boolean result = MerchantX509Cert.verifySign(signSrc,v_sign,publicKey);
            if (!result) {
                errorMessage = "check sign failed.";
                _log.error("Payeasepay Notify parameter {}", errorMessage);
                payContext.put("retMsg", errorMessage);
                return false;
            }
        } catch (Exception e) {
            _log.error(e, "");
        }

        return true;
    }

    /**
     * 验证首信易支付结果参数
     * @return
     */
    public boolean verifyPayReturnParams(Map<String, Object> payContext) {
        Map<String,String> params = (Map<String,String>)payContext.get("parameters");

        //校验结果是否成功
        String status = params.get("v_pstatus");
        if(status == null || !"20".equals(status)) {
            _log.error("status={}",status);
            payContext.put("retMsg", "notify data failed");
            return false;
        }

        String oid = params.get("v_oid");		// 商户订单号
        String total_amount = params.get("v_amount"); 		    // 支付金额
        if (org.springframework.util.StringUtils.isEmpty(oid)) {
            _log.error("Payeasepay Notify parameter oid is empty. oid={}", oid);
            payContext.put("retMsg", "oid is empty");
            return false;
        }
        if (org.springframework.util.StringUtils.isEmpty(total_amount)) {
            _log.error("Payeasepay Notify parameter total_amount is empty. total_amount={}", total_amount);
            payContext.put("retMsg", "total_amount is empty");
            return false;
        }
        String errorMessage;
        // 验证签名
        String publicKey = getCertFilePath(getChannelName(), PayeasepayConfig.pubkeyName);
        String signSrc = params.get("v_oid") + params.get("v_pstatus") + params.get("v_amount") + params.get("v_moneytype");
        String v_sign = params.get("v_sign");
        try {
            Boolean result = MerchantX509Cert.verifySign(signSrc, v_sign, publicKey);
            if (!result) {
                errorMessage = "check sign failed.";
                _log.error("Payeasepay Notify parameter {}", errorMessage);
                payContext.put("retMsg", errorMessage);
                return false;
            }
        } catch (Exception e) {
           _log.error(e, "");
        }

        // 查询payOrder记录
        String payOrderId = oid;
        PayOrder payOrder = commonService.payOrderService.findByPayOrderId(payOrderId);
        if (payOrder == null) {
            _log.error("Can't found payOrder form db. payOrderId={}, ", payOrderId);
            payContext.put("retMsg", "Can't found payOrder");
            return false;
        }

        // 核对金额
        BigDecimal outPayAmt = new BigDecimal(total_amount);
        BigDecimal dbPayAmt = new BigDecimal(AmountUtil.convertCent2Dollar(payOrder.getAmount() + ""));
        if (dbPayAmt.compareTo(outPayAmt) != 0) {
            _log.error("db payOrder record payPrice not equals total_amount. total_amount={},payOrderId={}", total_amount, payOrderId);
            payContext.put("retMsg", "");
            return false;
        }
        payContext.put("payOrder", payOrder);
        return true;
    }

    /**
     * 获取证书文件路径
     * @param channelName
     * @param fileName
     * @return
     */
    public String getCertFilePath(String channelName, String fileName) {
        return payConfig.getCertRootPath() + File.separator + channelName + File.separator + fileName;
    }


}
